#pragma once

#include <vector>

#include "renderer.h"

struct VertexBufferElement {
    uint32_t type;
    uint32_t count;
    uint8_t normalized;

    static uint32_t GetSizeOfType(uint32_t type)
    {
        switch(type) {
            case GL_FLOAT: return sizeof(GLfloat);
            case GL_UNSIGNED_INT: return sizeof(GLuint);
            case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
        }
        ASSERT(false);
        return 0;
    }
};

class VertexBufferLayout {
public:
    VertexBufferLayout() = default;

    template<typename T>
    void Push(uint32_t count)
    {
        ASSERT(false);
    }

    template<>
    void Push<float>(uint32_t count)
    {
        elements_.push_back({ GL_FLOAT, count, GL_FALSE });
        stride_ += count * VertexBufferElement::GetSizeOfType(GL_FLOAT);
    }

    template<>
    void Push<uint32_t>(uint32_t count)
    {
        elements_.push_back({ GL_UNSIGNED_INT, count, GL_FALSE });
        stride_ += count * VertexBufferElement::GetSizeOfType(GL_UNSIGNED_INT);
    }

    template<>
    void Push<uint8_t>(uint32_t count)
    {
        elements_.push_back({ GL_UNSIGNED_BYTE, count, GL_TRUE });
        stride_ += count * VertexBufferElement::GetSizeOfType(GL_UNSIGNED_BYTE);
    }

    inline const std::vector<VertexBufferElement>& GetElements() const { return elements_; }
    inline uint32_t GetStride() const { return stride_; }

private:
    std::vector<VertexBufferElement> elements_;
    uint32_t stride_ = 0;
};
